﻿using BUGCOME.Infrastructure.Attribute;
using BUGCOME.Infrastructure.IPTools;
using BUGCOME.Infrastructure.Model;
using BUGCOME.Model.Auth;
using BUGCOME.Model.Auth.dto;
using BUGCOME.Service.Auth.IServices;
using BUGCOME.ServiceCore.Services.IServices;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;

namespace BUGCOME.Service.Auth
{
    /// <summary>
    /// 用户基础信息服务类，继承自通用基础服务并实现用户基础服务接口
    /// </summary>
    /// <remarks>
    /// 负责处理与用户基础信息相关的核心业务逻辑，包括用户注册、登录、信息维护等
    /// 同时依赖角色服务、用户详情服务等处理关联业务操作
    /// </remarks>
    [AppService(ServiceType = typeof(IUserBaseService), ServiceLifetime = LifeTime.Transient)]
    public class UserBaseService : BaseService<UserBase>, IUserBaseService
    {
        /// <summary>
        /// 角色服务接口实例，用于处理用户角色关联、角色权限等相关业务操作
        /// </summary>
        private readonly IRoleService roleService;

        /// <summary>
        /// 用户个人信息服务接口实例，用于处理个人用户的详细信息管理
        /// </summary>
        private readonly IUserIndividualService userIndividualService;

        /// <summary>
        /// 用户系统信息服务接口实例，用于处理系统用户的相关信息管理
        /// </summary>
        private readonly IUserSystemService userSystemService;

        /// <summary>
        /// 用户团队信息服务接口实例，用于处理团队用户的团队信息管理
        /// </summary>
        private readonly IUserTeamService userTeamService;

        /// <summary>
        /// 团队成员服务接口实例，用于处理团队成员的关联关系管理
        /// </summary>
        private readonly ITeamMemberService teamMemberService;

        /// <summary>
        /// 构造函数，通过依赖注入初始化所需的服务实例
        /// </summary>
        /// <param name="roleService">角色服务接口实例</param>
        /// <param name="userIndividualService">用户个人信息服务实例</param>
        /// <param name="userSystemService">用户系统信息服务实例</param>
        /// <param name="userTeamService">用户团队信息服务实例</param>
        /// <param name="teamMemberService">团队成员服务实例</param>
        /// <remarks>
        /// 使用构造函数注入模式，确保服务依赖清晰可见，便于测试和维护
        /// 所有依赖服务均为接口类型，符合依赖倒置原则
        /// </remarks>
        public UserBaseService(IRoleService roleService,
            IUserIndividualService userIndividualService,
            IUserSystemService userSystemService,
            IUserTeamService userTeamService,
            ITeamMemberService teamMemberService
            )
        {
            this.roleService = roleService;
            this.userIndividualService = userIndividualService;
            this.userSystemService = userSystemService;
            this.userTeamService = userTeamService;
            this.teamMemberService = teamMemberService;
        }

        /// <summary>
        /// 检查指定手机号已绑定的用户ID列表
        /// </summary>
        /// <param name="phoneNum">待检查的手机号码</param>
        /// <returns>绑定该手机号的用户ID列表，无匹配时返回空列表</returns>
        /// <remarks>
        /// 用于判断手机号是否已被使用，支持同一手机号绑定多个用户的业务场景
        /// 实际应用中可能需要根据业务需求限制为唯一绑定
        /// </remarks>
        public async Task<List<long>> CheckPhoneBindAsync(string phoneNum)
        {
            // 根据手机号查询所有匹配的用户记录
            var list = await GetListAsync(it => it.Phone == phoneNum);
            // 提取用户ID列表
            var temp = list.Select(x => x.Id).ToList();
            // 确保返回非null的列表（空列表表示无绑定）
            return list.Count > 0 ? temp : new List<long>();
        }

        /// <summary>
        /// 根据登录信息进行用户认证
        /// </summary>
        /// <param name="user">包含登录凭证的DTO对象，包含用户名/邮箱、密码、用户类型</param>
        /// <returns>认证成功返回用户实体，失败返回null</returns>
        /// <remarks>
        /// 认证逻辑说明：
        /// 1. 支持用户名或邮箱两种登录方式
        /// 2. 验证用户类型是否匹配
        /// 3. 密码比较采用全小写匹配（需确保数据库存储的是小写哈希值）
        /// 4. 检查用户是否被删除（DelFlag=0表示未删除）
        /// 
        /// 安全建议：
        /// - 实际生产环境应使用更安全的密码哈希算法（如BCrypt）
        /// - 建议添加登录失败次数限制和临时锁定机制
        /// - 考虑添加验证码机制防止暴力破解
        /// </remarks>
        public async Task<UserBase> LoginAsync(LoginDto user)
        {
            return await GetFirstAsync(it => it.UserName == user.Username  &&
                it.DelFlag == 0);
        }

        /// <summary>
        /// 绑定用户手机号码
        /// </summary>
        /// <param name="uid">用户ID</param>
        /// <param name="phoneNum">待绑定的手机号码</param>
        /// <returns>数据库操作影响的行数（1表示成功，0表示失败）</returns>
        /// <remarks>
        /// 实现方式：使用部分字段更新，仅修改用户的Phone字段
        /// 实际应用中应先验证手机号格式和唯一性
        /// </remarks>
        public async Task<long> PhoneBindAsync(long uid, string phoneNum)
        {
            return await UpdateAsync(
                new UserBase() { Phone = phoneNum },
                it => new { it.Phone },  // 仅更新Phone字段
                f => f.Id == uid         // 条件：用户ID匹配
            );
        }

        /// <summary>
        /// 异步注册新用户并返回注册结果
        /// </summary>
        /// <param name="dto">注册请求数据传输对象，包含用户名、密码、用户类型等信息</param>
        /// <returns>ApiResult对象，包含注册成功/失败信息及用户数据（成功时）</returns>
        /// <exception cref="CustomException">
        /// 当用户名已存在时抛出此异常
        /// </exception>
        /// <remarks>
        /// 完整注册流程：
        /// 1. 密码强度验证（通过Tools.PasswordStrength方法）
        /// 2. 用户名格式验证（通过Tools.CheckUserName方法）
        /// 3. 生成唯一GUID作为用户标识
        /// 4. 使用HMACSHA256算法加密密码（加盐值为GUID的第一段）
        /// 5. 通过IP地址解析用户地理位置信息
        /// 6. 构建用户基础信息实体
        /// 7. 检查用户名在指定用户类型中是否唯一
        /// 8. 使用事务确保数据一致性：
        ///    - 插入用户基础信息
        ///    - 插入用户个人信息（所有用户类型都需要）
        ///    - 根据用户类型插入系统信息或团队信息
        ///    - 团队用户额外添加团队成员记录（自己作为管理员）
        /// </remarks>
        public async Task<ApiResult> RegisterAsync(RegisterDto dto)
        {
            // 验证密码强度
            if (!Tools.PasswordStrength(dto.Password))
            {
                return ApiResult.Error("密码强度不符合要求");
            }

            // 校验用户名格式
            if (!Tools.CheckUserName(dto.Username))
            {
                return ApiResult.Error("用户名不符合要求");
            }

            // 查询是否存在相同用户名和类型的用户
            var existingUser = await GetFirstAsync(it =>
                it.UserName == dto.Username &&
                it.DelFlag == 0);

            UserBase? user = null;
            bool isNewUser = existingUser == null;

            // 生成加密参数（新用户需要）
            string? guid = isNewUser ? Guid.NewGuid().ToString() : null;
            string? password = isNewUser
                ? NETCore.Encrypt.EncryptProvider.HMACSHA256(dto.Password, guid.Split('-')[0])
                : null;

            // IP地址解析（新用户需要）
            var ip_info = isNewUser ? IpTool.Search(dto.UserIP) : null;

            // 事务处理注册逻辑
            var result = await UseTranAysnc(async () =>
            {
                if (isNewUser)
                {
                    // 新用户：创建完整信息（基础信息+个人信息+扩展信息）
                    user = new UserBase()
                    {
                        Guid = guid,
                        CreateTime = DateTime.Now,
                        UserType = dto.UserType,
                        UserName = dto.Username,
                        NickName = dto.Username,
                        Password = password,
                        LoginIP = dto.UserIP,
                        Status = 1,
                        Remark = "用户注册",
                        Province = ip_info.Province,
                        City = ip_info.City
                    };

                    // 插入用户基础信息
                    user.Id = await Insertable(user).ExecuteReturnSnowflakeIdAsync();

                    // 创建个人信息
                    UserIndividual userIndividual = new UserIndividual()
                    {
                        UserId = user.Id,
                        BirthDate = Convert.ToDateTime("1900-01-01"),
                        Gender = dto.UserType,
                        MembershipLevel = 0,
                        IsActive = true,
                    };
                    user.UserIndividualNav = await userIndividualService.AddUserIndividualAsync(userIndividual);
                }
                else
                {
                    // 已有用户：复用现有基础信息和个人信息
                    user = existingUser;

                    // 检查是否已存在对应扩展信息
                    switch (dto.UserType)
                    {
                        case "1":
                            throw new CustomException("该用户已存在用户信息，无需重复添加");
                            break;
                        case "2":
                            var existingSystem = await userSystemService.GetByIdAsync(user.Id);
                            if (existingSystem != null)
                            {
                                throw new CustomException("该用户已存在系统用户信息，无需重复添加");
                            }
                            break;
                        case "3":
                            var existingTeam = await userTeamService.GetByIdAsync(user.Id);
                            if (existingTeam != null)
                            {
                                throw new CustomException("该用户已存在团队用户信息，无需重复添加");
                            }
                            break;
                    }
                }

                // 添加对应类型的扩展信息（新用户和已有用户都执行）
                switch (dto.UserType)
                {
                    case "2":
                        // 添加系统用户信息
                        UserSystem userSystem = new UserSystem()
                        {
                            UserId = user.Id.ToString(),
                            Status = 1,
                            IsAudit = 0
                        };
                        user.UserSystemNav = await userSystemService.AddUserSystemAsync(userSystem);
                        break;

                    case "3":
                        // 添加团队用户信息
                        UserTeam userTeam = new UserTeam()
                        {
                            UserId = user.Id.ToString(),
                            Status = 1,
                            IsAudit = 0,
                            TeamName = isNewUser ? $"团队_{guid.Split('-')[1]}" : $"团队_{user.Guid.Split('-')[1]}",
                            TeamDescription = "新注册团队",
                            TeamLogo = string.Empty,
                            EstablishedTime = DateTime.Now
                        };
                        user.UserTeamNav = await userTeamService.AddUserTeamAsync(userTeam);

                        // 添加团队成员记录
                        TeamMember member = new TeamMember()
                        {
                            TeamUserId = user.Id,
                            IndividualUserId = user.Id,
                            JoinDate = DateTime.Now,
                            IsPrimaryAdmin = true,
                            AdminLevel = 1,
                            Status = 1
                        };
                        if (user.UserTeamNav.TeamMemberList == null)
                        {
                            user.UserTeamNav.TeamMemberList = new List<TeamMember>();
                        }
                        await teamMemberService.AddTeamMemberAsync(member);
                        user.UserTeamNav.TeamMemberList.Add(member);
                        break;
                }
            });

            // 返回结果
            return result.IsSuccess
                ? ApiResult.Success(
                    isNewUser ? "注册成功！" : "信息补充成功！",
                    user)
                : ApiResult.Error("操作失败！错误消息：" + result.ErrorMessage);
        }

        /// <summary>
        /// 校验用户名在指定用户类型中是否唯一
        /// </summary>
        /// <param name="userName">待校验的用户名</param>
        /// <param name="userType">用户类型，默认为"0"</param>
        /// <returns>存在返回true，不存在返回false</returns>
        /// <remarks>
        /// 仅检查未删除的用户（DelFlag=0），确保逻辑删除的用户不影响新用户注册
        /// </remarks>
        public async Task<bool> CheckUserNameUniqueAsync(string userName, string userType = "0")
        {
            // 统计符合条件的用户数量
            int count = await CountAsync(it =>
                it.UserName == userName &&
                it.UserType == userType &&
                it.DelFlag == 0);

            // 大于0表示用户名已存在
            return count > 0;
        }

        /// <summary>
        /// 更新用户的登录信息（最后登录IP和时间）
        /// </summary>
        /// <param name="loginIP">用户登录的IP地址</param>
        /// <param name="userId">用户ID</param>
        /// <remarks>
        /// 使用部分更新提高效率，仅修改LoginIP和LoginDate两个字段
        /// 通常在用户登录成功后调用此方法
        /// </remarks>
        public async Task UpdateLoginInfoAsync(string loginIP, long userId)
        {
            await UpdateAsync(
                new UserBase()
                {
                    LoginIP = loginIP,
                    LoginDate = DateTime.Now,
                    Id = userId
                },
                it => new { it.LoginIP, it.LoginDate }  // 仅更新这两个字段
            );
        }

        /// <summary>
        /// 异步重置指定用户的登录密码
        /// </summary>
        /// <param name="id">待重置密码的用户ID</param>
        /// <param name="pwd">已加密的新密码字符串</param>
        /// <returns>受影响的记录行数（1表示成功）</returns>
        /// <remarks>
        /// 方法仅负责更新密码字段，调用前需确保密码已正确加密
        /// 实际应用中应添加权限验证和操作日志记录
        /// </remarks>
        public async Task<long> ResetPwdAsync(long id, string pwd)
        {
            return await UpdateAsync(
                new UserBase() { Id = id, Password = pwd },
                it => new { it.Password },  // 仅更新密码字段
                f => f.Id == id                 // 条件：用户ID匹配
            );
        }

        /// <summary>
        /// 异步根据用户ID查询用户基础信息，并加载关联的角色数据
        /// </summary>
        /// <param name="userid">待查询的用户ID</param>
        /// <returns>
        /// 包含用户基础信息及关联角色数据的UserBase对象，用户不存在则返回null
        /// </returns>
        /// <remarks>
        /// 查询优化：
        /// - 使用5分钟缓存减少数据库访问
        /// - 自动过滤已删除的用户（DelFlag=0）
        /// 
        /// 数据加载：
        /// - 自动加载用户关联的角色列表
        /// - 提取角色ID数组方便权限判断
        /// </remarks>
        public async Task<UserBase> SelectUserByIdAsync(long userid)
        {
            // 查询用户基础信息，使用5分钟缓存
            var user = await Queryable()
                .Filter(null, true)
                .WithCache(60 * 5)  // 缓存5分钟
                .Where(f => f.Id == userid && f.DelFlag == 0)
                .FirstAsync();

            // 若用户存在，加载其关联的角色信息
            if (user != null && user.Id > 0)
            {
                // 获取用户角色列表
                user.Roles = await roleService.SelectUserRoleListByUserIdAsync(userid);
                // 提取角色ID数组
                user.RoleIds = user.Roles.Select(x => x.RoleId).ToArray();
            }

            return user;
        }
    }
}